package com.zmn.mcc.business.impl.dept;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.mcc.business.interfaces.dept.DeptBService;
import com.zmn.mcc.cache.DeptCache;
import com.zmn.mcc.common.constant.DpermitConsts;
import com.zmn.mcc.common.constant.StaffConsts;
import com.zmn.mcc.common.constant.SystemConsts;
import com.zmn.mcc.common.dto.dept.DeptEditMessageDRO;
import com.zmn.mcc.model.dto.OrgDeptDto;
import com.zmn.mcc.model.entity.dept.McDept;
import com.zmn.mcc.model.entity.dept.McDeptQuery;
import com.zmn.mcc.model.entity.organize.McOrganize;
import com.zmn.mcc.persistence.interfaces.dept.DeptDao;
import com.zmn.mcc.services.interfaces.dept.DeptService;
import com.zmn.mcc.services.interfaces.organize.OrganizeService;
import com.zmn.mcc.services.interfaces.staff.StaffService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author heguanghua
 * @since 2020/04/14 21:54
 */
@Service
public class DeptBServiceImpl implements DeptBService {
    protected Logger logger = LoggerFactory.getLogger(DeptBServiceImpl.class);

    @Resource
    private DeptService deptService;
    @Resource
    private StaffService staffService;

    @Resource
    private OrganizeService organizeService;

    @Resource
    private DeptCache deptCache;

    @Resource
    private DeptDao deptDao;

    @Resource
    private ZmnMQSender zmnMQSender;

    @Value("${spring.mq.topic.mcc}")
    public String mccTopic;

    public static final String SYNC_EDIT_DEPT_KEY = "sync_edit_dept_key";


    // region 取得指定组织的部门列表

    @Override
    @ReadOnlyConnection
    public List<McDept> listDeptForAbove(Integer deptId, Boolean hasSelf) {

        List<McDept> items = new ArrayList<>();

        McDept dept = deptService.findByKey(deptId);
        this.getParentDept(dept, items);
        if (hasSelf) {
            items.add(dept);
        }
        return items;
    }

    private void getParentDept(McDept dept, List<McDept> items) {
        if (NumberUtil.isNotNullOrZero(dept.getParentId()) && dept.getParentId() > GlobalConsts.TOP_ID) {
            McDept parent = deptService.findByKey(dept.getParentId());
            if (parent == null) {
                return;
            }
            items.add(0, parent);
            this.getParentDept(parent, items);
        }
    }
    // endregion

    // region 取得指定组织的部门列表

    @Override
    @ReadOnlyConnection
    public List<McDept> listDept(McDeptQuery query) {

        List<McDept> items = deptDao.listByQuery(query);
        Integer level = query.getLevel();
        Integer l = level == null ? 100 : level;
        return items.stream().filter(item -> {
            if (item.getLevel() == null) {
                return true;
            }
            return item.getLevel() <= l;
        }).collect(Collectors.toList());
    }
    // endregion

    // region 取得指定组织的部门列表

    @Override
    public List<VtDTO> listSubAllDeptIncludeSelf(List<Integer> deptIds, Integer status) {
        List<Integer> allDeptIds = new ArrayList<>();
        allDeptIds.addAll(deptIds);

        listSubDeptIds(allDeptIds, allDeptIds, status);
        McDeptQuery query = new McDeptQuery();
        query.setStatus(status);
        query.setDeptIds(allDeptIds);
        List<McDept> subAllIncludeSelf = deptService.listByQuery(query);

        if (CollectionUtils.isNotEmpty(subAllIncludeSelf)) {
            return subAllIncludeSelf.stream()
                    .map(e -> new VtDTO(e.getDeptId(), e.getDeptName()))
                    .collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    // endregion

    @Override
    public List<McDept> buildTreeDept(Integer orgId) {

        McDeptQuery query = new McDeptQuery();
        query.setStatus(GlobalConsts.YES);
        query.setOrgId(orgId);
        List<McDept> list = deptService.listByQuery(query);
        if (CollectionUtil.isNullOrEmpty(list)) {
            return Collections.emptyList();
        }

        // 根据父级id分组
        TreeMap<Integer, List<McDept>> deptMap = list.stream().collect(Collectors.groupingBy(McDept::getParentId,
                TreeMap::new, Collectors.toList()));

        // 构建tree
        return buildTreeOrganize(deptMap.firstEntry().getValue(), deptMap, null);

    }

    /**
     * 描述: 构建树形列表
     *
     * @param depts   depts
     * @param deptMap 根据父级id分组菜单
     * @param result  返回结果
     * @return java.util.List<com.zmn.mcc.model.entity.menu.McMenu>
     * @author jiafei
     * @since 2021/7/14 15:19
     */
    private List<McDept> buildTreeOrganize(List<McDept> depts, Map<Integer, List<McDept>> deptMap,
                                           List<McDept> result) {

        // menus 排序 根据sort排序
        depts = depts.stream()
                .sorted(Comparator.comparing(
                        dept -> Objects.isNull(dept.getSort()) ? 0 : dept.getSort()))
                .collect(Collectors.toList());

        // 初始化返回结果
        if (Objects.isNull(result)) {
            result = new ArrayList<>();
        }

        List<McDept> treeDepts = result;
        depts.forEach(organize -> {

            treeDepts.add(setShowTreeOrganizeName(organize));

            // 获取子级菜单
            List<McDept> subDepts = deptMap.get(organize.getDeptId());

            // 没有子级菜单结束
            if (Objects.isNull(subDepts)) {
                return;
            }
            buildTreeOrganize(subDepts, deptMap, treeDepts);
        });
        return treeDepts;
    }

    /**
     * 描述: 设置名称前缀
     * 例如: 	一级
     * --二级
     * ----三级
     * --一级
     * ----二级
     *
     * @param organize organize
     * @author jiafei
     * @since 2021/7/14 15:17
     */
    private McDept setShowTreeOrganizeName(McDept organize) {

        if (Objects.equals(organize.getParentId(), 1)) {
            return organize;
        }

        if (!NumberUtil.isPositiveInteger(organize.getLevel())) {
            McDept parent = Optional.ofNullable(deptService.findByKey(organize.getParentId())).orElse(new McDept());
            organize.setLevel(Objects.isNull(parent.getLevel()) ? 1 : parent.getLevel());
        }

        String str = "---";
        Supplier<String> supplier = str::toString;
        String prefix = Stream.generate(supplier).limit(organize.getLevel() - 1).collect(Collectors.joining());
        organize.setDeptName(prefix + organize.getDeptName());
        return organize;
    }

    // region 新增/修改部门

    @Override
    public ResponseDTO addDept(McDept dept) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkDept(dept);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initDept(dept);

            // 部门信息
            deptService.insert(dept);

            // 更新缓存
            deptCache.setDept(dept.getDeptId());
            deptCache.setSuborDeptId(dept.getDeptId());
            deptCache.setAboveDeptId(dept.getDeptId());

            return ResponseDTO.success(dept.getDeptId(), "新增部门成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]新增部门失败,dept:[%s],ex:[%s]", JSONObject.toJSONString(dept), ex.getMessage()));
            return ResponseDTO.fail("新增部门失败");
        }
    }

    @Override
    public ResponseDTO modifyDept(McDept dept) {

        try {

            // 校验
            ResponseDTO checkResult = this.checkDept(dept);
            if (!checkResult.isSuccess()) {
                return checkResult;
            }

            // 初始化
            this.initDept(dept);

            // 判断修改的父级部门是否为自己的子级部门，避免形成死循环
            List<Integer> deptList = deptCache.listSuborDeptId(dept.getDeptId());
            if (CollectionUtil.isNotNullOrEmpty(deptList) && deptList.contains(dept.getParentId())) {
                return ResponseDTO.fail("无法将当前部门的子部门设置为其父部门");
            }

            McDept deptDB = deptCache.getDept(dept.getDeptId());
            // 部门信息
            deptService.updateByKey(dept);

            // 更新子部门level
            if (!Objects.equals(deptDB.getLevel(), dept.getLevel())) {
                updateSubDeptLevel(dept.getDeptId(), dept.getLevel());
            }

            // 更新缓存
            deptCache.setDept(dept.getDeptId());
            deptCache.setSuborDeptId(dept.getDeptId());
            deptCache.setAboveDeptId(dept.getDeptId());

            // 更新员工的部门名称
            staffService.updateDeptNameByDeptId(dept.getDeptId(), dept.getDeptName());

            // 发送部门修改消息
            sendDeptMessage(dept, deptDB);

            return ResponseDTO.success(dept.getDeptId(), "修改部门成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]修改部门失败,dept:[%s],ex:[%s]", JSONObject.toJSONString(dept), ex.getMessage()));
            return ResponseDTO.fail("修改部门失败");
        }
    }

    /**
     * 描述: 根据父部门Id更新子部门level
     *
     * @param parentId    父部门id
     * @param parentLevel 父部门level
     * @author jiafei
     * @since 2021/10/11 9:38
     */
    private void updateSubDeptLevel(Integer parentId, Integer parentLevel) {

        List<McDept> mcDepts = deptService.listByParentId(parentId);
        if (CollectionUtil.isNullOrEmpty(mcDepts)) {
            return;
        }
        // 跟新子部门level
        deptDao.updateLevelByParentId(parentId, parentLevel + 1);

        // 迭代是否仍有子级
        mcDepts.forEach(x -> updateSubDeptLevel(x.getDeptId(), parentLevel + 1));

    }


    /**
     * 校验部门信息
     *
     * @param dept
     * @return
     */
    private ResponseDTO checkDept(McDept dept) {

        if (StringUtil.isBlank(dept.getDeptName())) {
            return ResponseDTO.fail("部门名称不能为空");
        }
        if (NumberUtil.isNullOrZero(dept.getOrgId())) {
            return ResponseDTO.fail("未指定组织");
        }

        return ResponseDTO.success(null, "OK");
    }

    /**
     * 初始化部门
     *
     * @param dept
     */
    private void initDept(McDept dept) {

        if (NumberUtil.isNullOrZero(dept.getParentId())) {
            dept.setParentId(GlobalConsts.TOP_ID);
        }

        // 部门默认角色(新增时用)
        if (NumberUtil.isNullOrZero(dept.getDeptId())) {
            this.initDeptRole(dept, dept.getParentId());
        }

        // 默认继承数据权限的上级部门
        this.initDeptDpermitDept(dept, dept.getParentId());

        // 部门层级
        Integer level = 0;
        if (NumberUtil.isNotNullOrZero(dept.getParentId()) && dept.getParentId() > GlobalConsts.TOP_ID) {
            McDept parent = deptService.findByKey(dept.getParentId());
            level = Optional.ofNullable(parent.getLevel()).orElse(GlobalConsts.TOP_ID);
            level += 1;
        } else {
            level = GlobalConsts.TOP_ID;
        }
        dept.setLevel(level);
    }

    // 迭代寻找上级的roleId
    private void initDeptRole(McDept dept, Integer parentId) {
        if (NumberUtil.isNullOrZero(dept.getRoleId())
                && NumberUtil.isNotNullOrZero(parentId)
                && parentId > GlobalConsts.TOP_ID) {

            McDept parent = deptService.findByKey(parentId);
            dept.setRoleId(parent.getRoleId());
            if (NumberUtil.isNullOrZero(dept.getRoleId())) {
                this.initDeptRole(dept, parent.getParentId());
            }
        }
    }

    // 迭代寻找上级的dpermitDeptId
    private void initDeptDpermitDept(McDept dept, Integer parentId) {
        if (NumberUtil.isNullOrZero(dept.getDpermitDeptId())
                && NumberUtil.isNotNullOrZero(parentId)
                && parentId > GlobalConsts.TOP_ID) {

            McDept parent = deptService.findByKey(parentId);
            dept.setDpermitDeptId(parent.getDpermitDeptId());
            if (NumberUtil.isNullOrZero(dept.getDpermitDeptId())) {
                this.initDeptDpermitDept(dept, parent.getParentId());
            }
        }
    }
    // endregion

    // region 修改部门默认角色

    @Override
    public ResponseDTO modifyDeptRoleId(Integer deptId, Integer roleId, String updater) {

        // 校验参数
        if (NumberUtil.isNullOrZero(deptId)) {
            return ResponseDTO.fail("未指定部门");
        }
        if (NumberUtil.isNullOrZero(roleId)) {
            return ResponseDTO.fail("未指定角色");
        }

        try {

            // 修改默认角色
            deptService.updateRoleId(deptId, roleId, updater);

            // 更新缓存
            deptCache.setDept(deptId);

            return ResponseDTO.success(deptId, "修改部门默认角色成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]修改部门默认角色出错,deptId:[%s],roleId:[%s],ex:[%s]", deptId, roleId, ex.getMessage()));
            return ResponseDTO.fail("修改部门默认角色失败");
        }
    }

    @Override
    public McDept findByKey(Integer deptId) {
        return deptService.findByKey(deptId);
    }

    @Override
    public OrgDeptDto findSuborOrgDept(Integer deptId) {
        if (null == deptId) {
            return null;
        }
        List<OrgDeptDto> orgDeptDtoList = deptCache.listOrgDept();
        if (null == orgDeptDtoList) {
            orgDeptDtoList = listOrgDeptDto();
            deptCache.setOrgDept(orgDeptDtoList);
        }

        if (CollectionUtil.isNullOrEmpty(orgDeptDtoList)) {
            return null;
        }
        OrgDeptDto orgDeptDto = orgDeptDtoList.stream()
                .filter(e -> deptId.equals(e.getDeptId())).findAny().orElse(null);
        return orgDeptDto;
    }

    @Override
    public OrgDeptDto findSuborOrgDeptByBsDeptId(Integer bsDeptId) {

        if (null == bsDeptId) {
            return null;
        }
        List<OrgDeptDto> orgDeptDtoList = deptCache.listOrgDept();
        if (null == orgDeptDtoList) {
            orgDeptDtoList = listOrgDeptDto();
            deptCache.setOrgDept(orgDeptDtoList);
        }

        if (CollectionUtil.isNullOrEmpty(orgDeptDtoList)) {
            return null;
        }
        OrgDeptDto orgDeptDto = orgDeptDtoList.stream()
                .filter(e -> bsDeptId.equals(e.getBsDeptId())).findAny().orElse(null);
        return orgDeptDto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseDTO modifyBeisenDeptId(Integer deptId, Integer bsDeptId, String updater) {

        int count = deptService.countByBsDeptIdAndNotDeptId(deptId, bsDeptId);
        if (count > 0) {
            return ResponseDTO.fail(121703, "该北森部门ID已被绑定，请核实后再试");
        }
        deptService.updateBsDeptIdByDeptId(deptId, bsDeptId, updater);

        // 更新缓存
        deptCache.setDept(deptId);
        deptCache.setSuborDeptId(deptId);
        deptCache.setAboveDeptId(deptId);
        deptCache.setOrgDept(listOrgDeptDto());
        return ResponseDTO.success(null, "操作成功！");
    }
    // endregion

    // region 递归查询下级部门
    private void listSubDeptIds(List<Integer> resultDeptIds, List<Integer> deptIds, Integer status) {
        if (CollectionUtils.isEmpty(deptIds)) {
            return;
        }
        List<McDept> items = deptService.listByParentIds(deptIds, status);
        if (CollectionUtils.isEmpty(items)) {
            return;
        }
        List<Integer> currentDeptIds = items.stream().map(e -> e.getDeptId()).collect(Collectors.toList());
        resultDeptIds.addAll(currentDeptIds);
        listSubDeptIds(resultDeptIds, currentDeptIds, status);
    }
    // endregion

    //查找所有部门的上级部门和上级组织
    private List<OrgDeptDto> listOrgDeptDto() {
        List<McDept> deptList = deptService.listValidDept();
        List<McOrganize> orgList = organizeService.listValidOrgs();
        List<OrgDeptDto> list = deptList.stream().map(e -> {
            OrgDeptDto orgDeptDto = new OrgDeptDto();
            orgDeptDto.setDeptId(e.getDeptId());
            orgDeptDto.setBsDeptId(e.getBsDeptId());
            return orgDeptDto;
        }).collect(Collectors.toList());
        Map<Integer, McDept> deptMap = deptList.stream()
                .collect(Collectors.toMap(McDept::getDeptId, e -> e, (e1, e2) -> e2));

        Map<Integer, McOrganize> orgMap = orgList.stream()
                .collect(Collectors.toMap(McOrganize::getOrgId, e -> e, (e1, e2) -> e2));
        for (OrgDeptDto orgDeptDto : list) {
            McDept dept = deptMap.get(orgDeptDto.getDeptId());
            orgDeptDto.addParentDeptId(dept.getDeptId());
            addSuborDeptId(orgDeptDto, dept.getParentId(), deptMap);

            McOrganize organize = orgMap.get(dept.getOrgId());
            if (null == organize) {
                continue;
            }
            orgDeptDto.addParentOrgId(organize.getOrgId());
            addSuborOrgId(orgDeptDto, organize.getParentId(), orgMap);
        }
        return list;
    }

    private void addSuborDeptId(OrgDeptDto orgDeptDto, Integer parentId, Map<Integer, McDept> deptMap) {
        if (!SystemConsts.ROOT_ID.equals(parentId)) {
            orgDeptDto.addParentDeptId(parentId);
            McDept parentDept = deptMap.get(parentId);
            if (!Objects.isNull(parentDept)) {
                addSuborDeptId(orgDeptDto, parentDept.getParentId(), deptMap);
            }
        }
    }

    private void addSuborOrgId(OrgDeptDto orgDeptDto, Integer parentId, Map<Integer, McOrganize> orgMap) {
        if (SystemConsts.ROOT_ID != parentId) {
            orgDeptDto.addParentOrgId(parentId);
            McOrganize parentOrg = orgMap.get(parentId);
            if (!Objects.isNull(parentOrg)) {
                addSuborOrgId(orgDeptDto, parentOrg.getParentId(), orgMap);
            }
        }
    }

    /**
     * 描述: 修改部门消息
     *
     * @param dept   部门信息
     * @param deptDB 原部门信息
     * @author fengxuecai
     * @since 2021/5/17 16:28
     */
    private void sendDeptMessage(McDept dept, McDept deptDB) {
        try {
            DeptEditMessageDRO deptEditMessage = new DeptEditMessageDRO();
            deptEditMessage.setDeptId(dept.getDeptId());
            deptEditMessage.setDeptName(dept.getDeptName());
            deptEditMessage.setLevel(dept.getLevel());
            deptEditMessage.setOldLevel(deptDB.getLevel());
            deptEditMessage.setUpdater(dept.getUpdater());
            // 设置上级全部部门信息
            setParentNames(dept.getParentId(), deptEditMessage);
            logger.info("部门修改发送mq消息,key:{},", SYNC_EDIT_DEPT_KEY);
            zmnMQSender.send(mccTopic, StaffConsts.SYNC_EDIT_DEPT_TAG, SYNC_EDIT_DEPT_KEY, JSON.toJSONString(deptEditMessage));
        } catch (Exception e) {
            logger.error("部门修改发送mq消息，msg:{}", e.getMessage());
        }
    }

    private void setParentNames(Integer parentId, DeptEditMessageDRO deptEditMessage) {
        McDept parentDept = deptService.findByKey(parentId);
        if (Objects.nonNull(parentDept)) {
            Integer level = parentDept.getLevel();
            if (level == DpermitConsts.DEPT_LEVEL_FOUR) {
                deptEditMessage.setDeptFourId(parentDept.getDeptId());
                deptEditMessage.setDeptFourName(parentDept.getDeptName());
            }
            if (level == DpermitConsts.DEPT_LEVEL_THRE) {
                deptEditMessage.setDeptThreeId(parentDept.getDeptId());
                deptEditMessage.setDeptThreeName(parentDept.getDeptName());
            }
            if (level == DpermitConsts.DEPT_LEVEL_TWO) {
                deptEditMessage.setDeptTwoId(parentDept.getDeptId());
                deptEditMessage.setDeptTwoName(parentDept.getDeptName());
            }
            if (level == DpermitConsts.DEPT_LEVEL_ONE) {
                deptEditMessage.setDeptOneId(parentDept.getDeptId());
                deptEditMessage.setDeptOneName(parentDept.getDeptName());
            }
            if (level != DpermitConsts.DEPT_LEVEL_ONE) {
                setParentNames(parentDept.getParentId(), deptEditMessage);
            }
        }
    }

}
